﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using QuantBox.Design;
using Skyline;

namespace QuantBox
{
    public partial class ChainDataForm : Form
    {
        private readonly QBHistoricalData _historicalData;
        private InstrumentData[] _instList;
        private InstrumentData[] _selectList;

        private readonly HashSet<string> _underlyingList = new HashSet<string>();

        public ChainDataForm(QBHistoricalData historicalData)
        {
            InitializeComponent();
            _historicalData = historicalData;
        }

        private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            if (e.RowIndex >= _selectList.Length - 1)
            {
                return;
            }
            var inst = _selectList[e.RowIndex];
            switch (e.ColumnIndex)
            {
                case 0:
                    e.Value = inst.Id;
                    break;
                case 1:
                    e.Value = inst.Exchange;
                    break;
                case 2:
                    e.Value = inst.ExchangeCode;
                    break;
                case 3:
                    e.Value = inst.UnderlyingId;
                    break;
                case 4:
                    e.Value = inst.ListedDate.ToString("yyyyMMdd");
                    break;
                case 5:
                    e.Value = inst.MaturityDate.ToString("yyyyMMdd");
                    break;
                default:
                    e.Value = string.Empty;
                    break;
            }
        }

        private void btnSetDataPath_Click(object sender, EventArgs e)
        {
            var folder = new FolderBrowser2();
            if (_historicalData.ChainDataPath != null)
            {
                folder.DirectoryPath = _historicalData.ChainDataPath;
            }
            if (folder.ShowDialog(this) == DialogResult.OK)
            {
                _historicalData.ChainDataPath = folder.DirectoryPath;
                LoadInstruments();
            }
        }

        private void ChainDataForm_Load(object sender, EventArgs e)
        {
            LoadInstruments();
        }

        private void LoadInstruments()
        {
            if (_historicalData.ChainDataPath == null || !Directory.Exists(_historicalData.ChainDataPath))
                return;

            var file = GetInstrumentFile();
            if (!File.Exists(file))
                return;

            _instList = JsonConvert.DeserializeObject<InstrumentData[]>(File.ReadAllText(file));
            _underlyingList.Clear();
            cmbUnderlying.Items.Clear();

            foreach (var inst in _instList)
            {
                if (!string.IsNullOrEmpty(inst.UnderlyingSymbol) && !_underlyingList.Contains(inst.UnderlyingSymbol))
                {
                    _underlyingList.Add(inst.UnderlyingSymbol);
                }
            }
            cmbUnderlying.Items.AddRange(_underlyingList.ToArray());
            _selectList = _instList;
            InstViewReload();
        }

        private void InstViewReload()
        {
            dataGridView.RowCount = 0;
            dataGridView.RowCount = _selectList.Length;
        }

        private string GetInstrumentFile()
        {
            return Path.Combine(_historicalData.ChainDataPath, "insts.json");
        }

        private IList<InstrumentData> GetInstruments(DateTime date)
        {
            var list = new List<InstrumentData>();
            var client = new DataCenterClient(_historicalData.dataCenterInfo);
            foreach (var type in new[] { DataCenterConst.Option })
            {
                var (names, _) = client.GetInstrumentNames(type, date, CancellationToken.None);
                foreach (var item in names.SplitItems())
                {
                    var (instruments, _) = client.GetInstruments(item, type, CancellationToken.None);
                    list.AddRange(instruments);
                }
            }

            var futureList = new HashSet<string>();
            var stockList = new HashSet<string>();
            foreach (var inst in list)
            {
                if (string.IsNullOrEmpty(inst.UnderlyingId))
                {
                    continue;
                }
                var underlying = string.Empty;
                var match = Regex.Match(inst.Symbol, @"(\w+)\d\d\d\d(认购|认沽)\d+");
                if (match.Success)
                {
                    underlying = match.Groups[1].Value;
                }
                inst.UnderlyingSymbol = underlying;
                if (inst.Type == DataCenterConst.FutureOption)
                {
                    if (!futureList.Contains(inst.UnderlyingId))
                    {
                        futureList.Add(inst.UnderlyingId);
                    }
                }
                else
                {
                    if (inst.Type == DataCenterConst.IndexOption)
                    {
                        if (inst.UnderlyingId.StartsWith("IO"))
                        {
                            inst.UnderlyingId = "000300.SH";
                        }
                    }
                    else if (inst.Type == DataCenterConst.Option)
                    {
                        if (inst.UnderlyingId.StartsWith("OP"))
                        {
                            inst.UnderlyingId = inst.UnderlyingId.Substring(2);
                        }
                    }
                    if (!stockList.Contains(inst.UnderlyingId))
                    {
                        stockList.Add(inst.UnderlyingId);
                    }
                }
            }

            {
                var (instruments, _) = client.GetInstruments(futureList.ToArray(), DataCenterConst.Future, CancellationToken.None);
                list.AddRange(instruments);
            }
            {
                var (instruments, _) = client.GetInstruments(stockList.ToArray(), DataCenterConst.Stock, CancellationToken.None);
                list.AddRange(instruments);
            }
            return list;
        }

        private void btnGetInstruments_Click(object sender, EventArgs e)
        {
            var task = Task.Run(() => GetInstruments(DateTime.MaxValue));
            while (!task.Wait(0))
            {
                Application.DoEvents();
            }
            File.WriteAllText(GetInstrumentFile(), JsonConvert.SerializeObject(task.Result));
            LoadInstruments();
        }

        private void cbxFilter_CheckedChanged(object sender, EventArgs e)
        {
            cmbUnderlying.Enabled = cbxFilter.Checked;
            if (!cmbUnderlying.Enabled)
            {
                _selectList = _instList;
                InstViewReload();
            }
        }

        private void cmbUnderlying_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectList = _instList.Where(n => n.UnderlyingSymbol == cmbUnderlying.Text).ToArray();
            InstViewReload();
        }
    }
}
